<?php

namespace app\service;

use app\model\OrderDao;
use app\model\UserDao;
use app\model\WechatLogDao;
use think\facade\Request;

/**
 * 微信服务商
 */
class WechatPartner
{

    public function curlPost($url = '', $postData = '', $options = array())
    {
        if (is_array($postData)) {
            $postData = http_build_query($postData);
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
        if (!empty($options)) {
            curl_setopt_array($ch, $options);
        }
        //https请求 不验证证书和host
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        //$cert = syspath('public/cert/apiclient_cert.pem');
        //$key = syspath('public/cert/apiclient_key.pem');
        $certPath = './cert_svc/apiclient_cert.pem';
        $keyPath = './cert_svc/apiclient_key.pem';
        curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
        curl_setopt($ch, CURLOPT_SSLCERT, $certPath);
        //默认格式为PEM，可以注释
        curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
        curl_setopt($ch, CURLOPT_SSLKEY, $keyPath);
        //第二种方式，两个文件合成一个.pem文件
        // curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');
        $data = curl_exec($ch);
        if ($errno = curl_errno($ch)) {
            $msg = curl_strerror($errno);
            show_error('CURL:' . $msg);
        }
        curl_close($ch);
        return $data;
    }

    private function send(string $method, string $url, string $data): array
    {
        $start = microtime(true);
        $log = new WechatLogDao();
        $log->save([
            'url' => $url,
            'request' => $data,
            'ip' => Request::ip(),
            'uid' => request()->uid,
        ]);
        if (strtoupper($method) === 'POST') {
            $ret = $this->curlPost($url, $data);
        } else {
            $ret = curl_get($url);
        }
        $time = (microtime(true) - $start) * 1000;
        $log->save([
            'response' => $ret,
            'time' => $time,
        ]);
        return [$ret, $log->id];
    }

    /**
     * 服务商-代商户下单
     * https://pay.weixin.qq.com/doc/v2/partner/4011936644
     * @param OrderDao $order
     * @param string $noticeUrl
     * @return array
     */

    public function createOrder(OrderDao $order, string $noticeUrl): array
    {
        $uid = $order->uid;
        $host = config('wechat.notify_host');
        $title = $order->goods_name;
        $money = $order->pay_money;
        $apiKey = config('wechat.svc_api_key');
        $openId = UserDao::where('id', $uid)->value('openid');
        $param['appid'] = config('wechat.svc_appid');
        $param['mch_id'] = config('wechat.svc_mch_id');
        $param['sub_appid'] = config('wechat.app_id');
        $param['sub_mch_id'] = config('wechat.mch_id');
        $param['nonce_str'] = Weixin::randomkeys(16);
        $param['body'] = $title;
        $param['out_trade_no'] = $order->order_num;
        $param['total_fee'] = (int)($money * 100);
        $ip = Request::ip();
        $param['spbill_create_ip'] = $ip;
        $param['notify_url'] = $host . $noticeUrl;
        $param['trade_type'] = 'JSAPI';
        //$param['openid'] = $openId;
        $param['sub_openid'] = $openId;
        $param['profit_sharing'] = 'Y';//分账---很重要，否则无法分账
        $param['sign'] = Weixin::MakeSign($param, $apiKey);
        //$param['sign'] = $this->MakeSign($param);
        $data = Weixin::ToXml($param);
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        list($result, $logId) = $this->send('POST', $url, $data);
        $result = Weixin::fromXml($result);
        WechatLogDao::where('id', $logId)->update([
            'code' => $result['return_code'] ?? 'FAIL'
        ]);
        if (!empty($result['err_code_des'])) {
            show_error($result['err_code_des']);
        }
        if (isset($result['return_code']) && $result['return_code'] == 'SUCCESS' && !empty($result['appid'])) {
            $pay['appId'] = config('wechat.app_id');
            $pay['timeStamp'] = (string)time();
            $pay['package'] = 'prepay_id=' . $result['prepay_id'];
            $pay['nonceStr'] = $result['nonce_str'];
            $pay['signType'] = 'MD5';
            $pay['paySign'] = Weixin::MakeSign($pay, $apiKey);
            return $pay;
        }
        return $result;
    }


    /**
     * 给服务商-分账
     * @link https://pay.weixin.qq.com/doc/v2/partner/4011984565
     * @return array
     */
    public function transfer(OrderDao $order, $money): array
    {
        $url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharing';
        $postData = [
            'mch_id' => config('wechat.svc_mch_id'),//服务商商户号
            'sub_mch_id' => config('wechat.mch_id'),//子商户号，即分账的出资商户号
            'appid' => config('wechat.svc_appid'),//服务商appid
            'sub_appid' => config('wechat.app_id'),//appid
            'nonce_str' => Weixin::randomkeys(16),
            'transaction_id' => $order->transaction_id,//微信支付订单号
            'out_order_no' => $order->order_num,//服务商系统内部的分账单号
            'receivers' => json_encode([[
                'type' => 'MERCHANT_ID',
                'account' => config('wechat.svc_mch_id'),
                'amount' => intval($money * 100),
                'description' => '手续费分账到服务商',
            ]], JSON_UNESCAPED_UNICODE)
        ];
        $postData['sign'] = Weixin::MakeSign($postData, config('wechat.svc_api_key'), 'sha256');
        $xml = Weixin::ToXml($postData);
        list($rs, $logId) = $this->send('POST', $url, $xml);
        $ret = Weixin::FromXml($rs);
        if (!empty($ret['err_code_des'])) {
            WechatLogDao::where('id', $logId)->save([
                'code' => $ret['err_code'] ?? 'FAIL',
                'message' => $ret['err_code_des'],
            ]);
        } elseif (!empty($ret['result_code'])) {
            WechatLogDao::where('id', $logId)->save([
                'code' => $ret['result_code'],
                'message' => $ret['return_code'] ?? null,
            ]);
        }
        return $ret;
    }

    /**
     * 添加分账接收方<br>
     * <b>注意</b>：分账前添加，调用一次就够
     * @link https://pay.weixin.qq.com/doc/v2/partner/4011984782
     * @return array
     */
    public function addReceiver(): array
    {
        $url = 'https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver';
        $postData = [
            'mch_id' => config('wechat.svc_mch_id'),
            'sub_mch_id' => config('wechat.mch_id'),
            'appid' => config('wechat.svc_appid'),
            'nonce_str' => Weixin::randomkeys(16),
            //'sign_type' => 'HMAC-SHA256',//默认
            'receiver' => json_encode([
                'type' => 'MERCHANT_ID',
                'name' => '深圳市汇天下信息科技有限公司',
                'account' => config('wechat.svc_mch_id'),
                'relation_type' => 'SERVICE_PROVIDER',
            ])
        ];
        $postData['sign'] = Weixin::MakeSign($postData, config('wechat.svc_api_key'), 'sha256');
        $xml = Weixin::ToXml($postData);
        list($rs, $logId) = $this->send('POST', $url, $xml);
        $ret = Weixin::fromXml($rs);
        if (!empty($ret['return_code'])) {
            WechatLogDao::where('id', $logId)->save([
                'code' => $ret['return_code'],
                'message' => $ret['return_msg'],
            ]);
        }
        return $ret;
    }

    /**
     * 退款
     * @link https://pay.weixin.qq.com/doc/v2/partner/4011941447
     * @return array
     */
    public function refund(OrderDao $order)
    {
        $url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
        $postData = [
            'appid' => config('wechat.svc_appid'),
            'mch_id' => config('wechat.svc_mch_id'),
            'sub_mch_id' => config('wechat.mch_id'),
            'nonce_str' => Weixin::randomkeys(16),
            'transaction_id' => $order->transaction_id,
            'out_refund_no' => 'refund_' . getOrderNo($order->uid),
            'total_fee' => intval($order->pay_money * 100),
            'refund_fee' => intval($order->refund_money * 100),
            //'sign_type'=>'MD5',//默认md5
        ];
        $postData['sign'] = Weixin::MakeSign($postData, config('wechat.svc_api_key'));
        $xml = Weixin::ToXml($postData);
        list($rs, $logId) = $this->send('POST', $url, $xml);
        $ret = Weixin::fromXml($rs);
        if (!empty($ret['err_code_des'])) {
            WechatLogDao::where('id', $logId)->save([
                'code' => $ret['err_code'] ?? 'FAIL',
                'message' => $ret['err_code_des'],
            ]);
        } elseif (!empty($ret['result_code'])) {
            WechatLogDao::where('id', $logId)->save([
                'code' => $ret['result_code'],
                'message' => $ret['return_code'] ?? null,
            ]);
        }
        return $ret;
    }





}